package com.csust.automaticteach.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.csust.automaticteach.constant.OrderConstant;
import com.csust.automaticteach.exception.BusinessException;
import com.csust.automaticteach.exception.ErrorCode;
import com.csust.automaticteach.exception.ThrowUtils;
import com.csust.automaticteach.manager.cos.CosManager;
import com.csust.automaticteach.manager.cos.FileManager;
import com.csust.automaticteach.model.dto.file.UploadFileDetail;
import com.csust.automaticteach.model.dto.resource.ResourceQueryRequest;
import com.csust.automaticteach.model.entity.Resource;
import com.csust.automaticteach.model.entity.Space;
import com.csust.automaticteach.model.entity.User;
import com.csust.automaticteach.model.vo.generateteach.UploadReturnVO;
import com.csust.automaticteach.model.vo.resource.AdminResourceVO;
import com.csust.automaticteach.model.vo.resource.ResourceVO;
import com.csust.automaticteach.service.ResourceService;
import com.csust.automaticteach.mapper.ResourceMapper;
import com.csust.automaticteach.service.SpaceService;
import com.csust.automaticteach.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.multipart.MultipartFile;
import java.util.Date;
import java.util.List;
import static com.csust.automaticteach.constant.FileConstant.FILE_FAIL_DELETE;

/**
* @author 钰玟
* @description 针对表【t_resource(资源表)】的数据库操作Service实现
* @createDate 2025-07-16 22:20:24
*/
@Service
@Slf4j
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource>
    implements ResourceService{
    @jakarta.annotation.Resource
    private FileManager fileManager;
    @jakarta.annotation.Resource
    private CosManager cosManager;
    @jakarta.annotation.Resource
    private UserService userService;
    @jakarta.annotation.Resource
    private SpaceService spaceService;
    @jakarta.annotation.Resource
    private TransactionTemplate transactionTemplate;




    @Override
    public UploadReturnVO uploadResourceFile(MultipartFile file,Long spaceId, User loginUser) {
        String filename = file.getOriginalFilename();
        String fileType = null;
        if (filename != null && filename.contains(".")) {
            //防止出现 tensorflow.js  xxx .docx
            fileType = filename.substring(filename.lastIndexOf(".") + 1);
        }
        Long userId = loginUser.getId();
        //构造上传（至cos）文件的前缀 用户id+业务前缀 区分是否上传到空间
        String filePrefix = "";
        if (spaceId == null) {
            filePrefix = String.format("resource/%s", loginUser.getId());
        } else {
            filePrefix = String.format("space/%s", spaceId);
        }
        //空间级别和限额控制
        if (spaceId != null) {
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            // 必须空间创建人（管理员）才能上传
            if (!loginUser.getId().equals(space.getUserId())) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有空间权限");
            }
            // 校验额度
            if (space.getTotalCount() >= space.getMaxCount()) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "空间条数不足");
            }
            if (space.getTotalSize() >= space.getMaxSize()) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "空间大小不足");
            }
        }
        UploadFileDetail uploadFileDetail = fileManager.uploadFile(file, filePrefix);
        String url = uploadFileDetail.getUrl();
        Long fileSize = uploadFileDetail.getFileSize();
        Resource resource = new Resource();
        resource.setName(filename);
        String description = "有关" + filename + "的资源";
        resource.setDescription(description);
        resource.setUserId(userId);
        resource.setFileUrl(url);
        resource.setType(fileType);
        //格式化一下文件大小
        double FileSize = (double)fileSize/1024/1024;
        String formatFileSize = String.format("%.3f", FileSize);
        resource.setFileSize(formatFileSize +"MB");
        resource.setStatus(3);
        //入库  开启事务
        Long finalSpaceId = spaceId;
        Boolean executed = transactionTemplate.execute(status -> {
            boolean result = this.saveOrUpdate(resource);
            ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "资源上传失败");
            if (finalSpaceId != null) {
                boolean update = spaceService.lambdaUpdate()
                        .eq(Space::getId, finalSpaceId)
                        .setSql("totalSize = totalSize + " + resource.getFileSize())
                        .setSql("totalCount = totalCount + 1")
                        .update();
                ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "额度更新失败");
            }
            return result;
        });
        if(!executed){
            //删除cos文件
            String key = url.substring(url.lastIndexOf("//") + 1);
            try {
                cosManager.deleteFile(key);
            } catch (Exception e) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR);
            }
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        UploadReturnVO uploadReturnVO = new UploadReturnVO();
        uploadReturnVO.setId(resource.getId());
        uploadReturnVO.setFileUrl(url);
        return uploadReturnVO;
    }

    @Override
    public QueryWrapper<Resource> getResourceQueryWrapper(ResourceQueryRequest resourceQueryRequest) {
        //获取查询参数
        String name = resourceQueryRequest.getName();
        String category = resourceQueryRequest.getCategory();
        Long userId = resourceQueryRequest.getUserId();
        String searchText = resourceQueryRequest.getSearchText();
        Long spaceId = resourceQueryRequest.getSpaceId();
        String userName = resourceQueryRequest.getUserName();
        Integer status = resourceQueryRequest.getStatus();
        Integer intervalTime = resourceQueryRequest.getIntervalTime();
        boolean nullSpaceId = resourceQueryRequest.isNullSpaceId();
        String sortField = resourceQueryRequest.getSortField();
        String sortOrder = resourceQueryRequest.getSortOrder();

        //构建query对象
        QueryWrapper<Resource> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(ObjUtil.isNotNull(userId),"userId",userId);
        queryWrapper.like(StrUtil.isNotBlank(name),"name",name);
        queryWrapper.like(StrUtil.isNotBlank(userName),"userName",userName);
        queryWrapper.eq(StrUtil.isNotBlank(category),"category",category);
        queryWrapper.eq(ObjUtil.isNotNull(status),"status",status);
        queryWrapper.eq(ObjUtil.isNotNull(spaceId),"spaceId",spaceId);
        queryWrapper.isNull(nullSpaceId, "spaceId");
        queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), OrderConstant.ASC.equals(sortOrder), sortField);
        // 处理时间范围筛选
        if (ObjUtil.isNotNull(intervalTime)) {
            // 使用 MyBatis Plus 的 lt/gt 方法进行时间范围筛选
            // intervalTime <= 1 表示今天内，<= 364 表示一年内
            if (intervalTime <= 1) {
                // 默认设置为今天内
                queryWrapper.ge("publishTime", DateUtil.beginOfDay(new Date()));
            } else {
                // 按照 intervalTime 天前的时间进行筛选
                Date targetDate = DateUtil.offsetDay(new Date(), -intervalTime);
                queryWrapper.ge("publishTime", targetDate);
            }
        }
        // 处理搜索文本
        if(StrUtil.isNotBlank(searchText)){
            queryWrapper.like("name", searchText)
                    .or()
                    .like("description", searchText);
        }
        //返回query
        return queryWrapper;
    }

    @Override
    public ResourceVO getResourceVO(Resource record) {
        ResourceVO resourceVO = new ResourceVO();
        BeanUtil.copyProperties(record, resourceVO);
        return resourceVO;
    }

    @Override
    public List<ResourceVO> getResourceVOList(List<Resource> records) {
        return records.stream().map(this::getResourceVO).toList();
    }

    @Override
    public AdminResourceVO getAdminResourceVO(Resource record) {
        AdminResourceVO adminResourceVO = new AdminResourceVO();
        BeanUtil.copyProperties(record, adminResourceVO);
        User user = userService.getById(record.getUserId());
        adminResourceVO.setUserName(user.getUserName());
        return adminResourceVO;
    }

    @Override
    public List<AdminResourceVO> getAdminResourceVOList(List<Resource> records) {
        return records.stream().map(this::getAdminResourceVO).toList();
    }

    @Override
    public boolean deleteById(Long id, HttpServletRequest request) {
        Resource byId = this.getById(id);
        User loginUser = userService.getLoginUser(request);
        //引入空间逻辑
        Long spaceId = byId.getSpaceId();
        if (spaceId != null){
            Space space = spaceService.getById(spaceId);
            if (space == null){
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            }
            if (!loginUser.getId().equals(space.getUserId())) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有空间权限");
            }
        }
        // 开启事务
        Boolean executed = transactionTemplate.execute(status -> {
            String fileUrl = byId.getFileUrl();
            //https://automatic-teach-1325795131.cos.ap-guangzhou.myqcloud.com//user/1/2025-06-24_3040180999769259.doc
            String key = fileUrl.substring(fileUrl.lastIndexOf("//") + 1);
            try {
                cosManager.deleteFile(key);
            } catch (Exception e) {
                log.error("fail to delete the file,the reason is:{}", e.getMessage());
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, FILE_FAIL_DELETE);
            }
            boolean result = this.removeById(id);
            ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
            if (spaceId != null) {
                boolean update = spaceService.lambdaUpdate()
                        .eq(Space::getId, spaceId)
                        .setSql("totalSize = totalSize - " + byId.getFileSize())
                        .setSql("totalCount = totalCount - 1")
                        .update();
                ThrowUtils.throwIf(!update, ErrorCode.OPERATION_ERROR, "额度更新失败");
            }
            return true;
        });
        return executed;
    }
}




